Function.prototype.bind = function() {
    if (arguments.length < 2 && arguments[0] === undefined) {
        return this;
    }
    var thisObj = this,
        args = Array.prototype.slice.call(arguments),
        obj = args.shift();
    return function() {
        return thisObj.apply(obj, args.concat(Array.prototype.slice.call(arguments)));
    };
};
Function.bind = function() {
    var args = Array.prototype.slice.call(arguments);
    return Function.prototype.bind.apply(args.shift(), args);
}

function Gallery(url, phWidth, boxCount, boxMargin, showCaption) {
    this.url = url;
    this.phWidth = phWidth;
    this.boxCount = boxCount;
    this.boxMargin = boxMargin;
    this.showCaption = showCaption;
    this.boxSize = Math.floor(4 * (boxMargin + (phWidth - 6 * boxCount * boxMargin) / (4 * boxCount + 2)));
};

Gallery.prototype.itemsCount = 0;
Gallery.prototype.imageSrcs = [];
Gallery.prototype.images = [];
Gallery.prototype.captions = [];
Gallery.prototype.descriptions = [];
Gallery.prototype.imageCount = 0;

Gallery.prototype.processImages = function() {
    this.loadImage(this.imageSrcs.shift());
}
Gallery.prototype.loadImage = function(imageSrc) {
    var self = this;
    var img = new Image();

    img.onload = function() {
	self.images.push(img);
	    
	if (self.imageSrcs.length == 0) {
	    self.buildUI();
	}
	else {
	    self.processImages();
	}
    }
    
    img.src = imageSrc;
}
Gallery.prototype.scaleImage = function(i, maxHeight) {
    var self = this;

    //Scale the image to fit inside a box where boxSize is the width and height of the box.
    var settings = {
	url: this.images[i].src,
	rsW: this.boxSize,
	rsH: maxHeight,
	callback: function(newWidth, newHeight) {                                       
	    if (newWidth && newHeight) {
		self.images[i].width = newWidth;
		self.images[i].height = newHeight;						
	    }
	    
	    self.imageCount++;
	
	    //All images have been scaled.
	    if (self.imageCount == self.itemsCount) {
		self.addImages();
	    }
	},
	onerror: function(image) {
	    //Do nothing.
	}
    };

    scaleToFit(settings);
}
Gallery.prototype.buildUI = function() {
    var $dissolve, $outgoing, $incoming, $caption, $description;
    var $stage = $("#stage");
    var phMargin = Math.floor((this.phWidth - 6 * this.boxCount * this.boxMargin) / (4 * this.boxCount + 2));
    
    //Build UI.
    for (var i = 0; i < this.itemsCount; i++) {
	$dissolve = $("<div>");
	$outgoing = $("<div>");
	$incoming = $("<div>");
	$caption = $("<span>");
	$description = $("<span>");
	
	//$dissolve.attr("id", "dissolve");
	$dissolve.css({
	    "width" : this.boxSize + "px",
	    "height" : this.boxSize + "px",
	    "margin": this.boxMargin + "px"
	});
	$stage.css({
	    "padding": phMargin + "px",
	    "width": this.phWidth - phMargin - phMargin + "px"
	});
	
	$dissolve.addClass("dissolve");
	$outgoing.addClass("outgoing");
	$outgoing.addClass("opaque");
	$incoming.addClass("incoming");
	$incoming.addClass("transparent");
	$caption.addClass("caption");
	$description.addClass("description");

	$caption.html(this.captions[i]);
	$description.html(this.descriptions[i]);
	
	$outgoing.append($caption);
	$incoming.append($description);
	$dissolve.append($outgoing);
	$dissolve.append($incoming);
	$stage.append($dissolve);

	//Account for the height and positioning of the caption.
	var maxHeight = this.boxSize - $caption.height() - 5 - 5;
	
	this.scaleImage(i, maxHeight);
    }

    this.init();
}
Gallery.prototype.addImages = function() {
    var i = 0;
    var self = this;
    
    $(".dissolve").each(function(index) {
	var $outgoing =  $(this).find(".outgoing");
	var $caption = $(this).find(".caption");
	
	$outgoing.append(self.images[i]);

	//Get height of image as it is displayed on the page so that the top margin can be adjusted for vertical alignment.
	var $images = $outgoing.find("img");
	i++;
	//Account for the height and positioning of the caption.
	//images[0].style.marginTop = -(images[0].offsetHeight / 2) - caption.offsetHeight - 5 - 5 + "px";	
    });
}
Gallery.prototype.loadResources = function(css, js) {
    var head = document.getElementsByTagName("head")[0];
    var cssNode = null;
    var script = null;
    var i;
    
    //Load CSS.
    for (i = 0; i < css.length; i++) {
	cssNode = document.createElement("link");
	cssNode.type = "text/css";
	cssNode.rel = "stylesheet";
	cssNode.href = css[i];
	head.appendChild(cssNode);
    }
    
    //Load JavaScript.
    for (i = 0; i < js.length; i++) {
	script = document.createElement("script");
	script.type = "text/javascript";
	script.src = js[i];
	
	//Get spreadsheet data when last Javascript library has been loaded.
	if (i == js.length - 1) {
	    //script.onload = getSpreadsheetData(prefs.getString("url"));
	    if (true) {
		$(".description").overscroll({
		    thumbThickness: 10
		});
	    }
	}
	
	head.appendChild(script);
    }
}
Gallery.prototype.init = function() {
    var overscrollJS = "http://risegadgets.googlecode.com/svn/test/common/overscroll/jquery.overscroll.js";
    var overscrollCSS = "http://risegadgets.googlecode.com/svn/test/GoogleSpreadsheet/style/Overscroll.css";
    var jScrollPaneJS = "http://risegadgets.googlecode.com/svn/test/common/jScrollPane/script/jquery.jscrollpane.min.js";
    var jScrollPaneMouseWheelJS = "http://risegadgets.googlecode.com/svn/test/common/jScrollPane/script/jquery.mousewheel.js";
    var jScrollPaneCSS = "http://risegadgets.googlecode.com/svn/test/GoogleSpreadsheet/style/jScrollPane.css";
    var self = this;
    this._isClose = false;
    this.construct();

    //Load the appropriate external resources depending on whether or not swipe is enabled.
    //if (swipeEnabled) {
    if (true) {
	var css = new Array(overscrollCSS);
	var js = new Array(overscrollJS);
	
	this.loadResources(css, js);
    }
    else {
	var css = new Array(jScrollPaneCSS);
	var js = new Array(jScrollPaneMouseWheelJS, jScrollPaneJS);
	
	this.loadResources(css, js);
    }
		    
    return this;
}
Gallery.prototype.construct = function() {
    this.setupListeners();
}
Gallery.prototype.didShow = function() {
    //Read data from spreadsheet.
    this._getImages = function(json) {
	if (json) {
	    this.itemsCount = json.rows.length;
	    
	    for (var row = 0; row < json.rows.length; row++) {
		this.imageSrcs.push(json.rows[row].c[0].v);
		this.captions.push(json.rows[row].c[1].v);
		this.descriptions.push(json.rows[row].c[2].v);
	    }
	}
	this.processImages();
    }.bind(this);
    getData(this.url, 0, this._getImages, 2);
}
Gallery.prototype.setupListeners = function() {
    var self = this;

    this._clickHandler = function(event) {
        //var arr = document.querySelectorAll(self._elementSel);	//dissolve element
	var $outgoing, $incoming;
	
	if (self._isClose != true) {
	    $(".dissolve").each(function(index) {
		if (event.currentTarget == this) {
		    $(this).addClass("closeup");
		}
		else {
		    $(this).addClass("background");
		}
	    });
	    
	    self._isClose = true;
	}
	else {	//Has closeup class.
	    var closeClicked = false;
	    
	    $(".dissolve").each(function(index) {
		if (event.currentTarget == this) {
		    if ($(this).hasClass("closeup")) {
			$outgoing = $(this).find(".outgoing");
			$incoming = $(this).find(".incoming");
			
			$outgoing.toggleClass("transparent");
			$outgoing.toggleClass("opaque");
			$incoming.toggleClass("transparent");
			$incoming.toggleClass("opaque");

			closeClicked = true;
			return false;
			//break;
		    }
		}
	    });
	    
	    if (!closeClicked) {	//Background clicked.
		$(".dissolve").each(function(index) {
		    if ($(this).hasClass("closeup")) {
			$(this).css("zIndex", 5);
			//Use bind.
			//$(this).addEventListener('webkitTransitionEnd', function() {	//THis doesn't work.
			//    $(this).css("zIndex", "");
			//    $(this).removeEventListener('webkitTransitionEnd', arguments.callee, false);
			//}, false);
			$(this).removeClass("closeup");
		    }
		    else {
			$(this).removeClass("background");
		    }
		});
		
		self._isClose = false;
	    }
	}
	
        arr = null;
    }
    
    $(".dissolve").each(function(index) {
        this.addEventListener('click', self._clickHandler, false);
    });
}
Gallery.init = function() {
    window.gallery = (new Gallery("https://spreadsheets1.google.com/a/risevision.com/tq?key=0Ap8mR-BSzMkLdFpmdUkwZzhqUlBTYldDVGduWXhFenc&headers=1", 800, 3, 5, true));
    if (!window.isLoaded) {
        window.gallery.didShow();
    }
}
if (window.isLoaded) {
    Gallery.init();
}
else {
    window.addEventListener('load', Gallery.init, 'false');
}